<template>
  <div class="app-container">
    <!-- 支付信息 -->
    <el-card v-loading="loading">
      <el-descriptions title="支付信息" :column="3" border>
        <el-descriptions-item label="支付单号">{{ payOrder.appId }}</el-descriptions-item>
        <el-descriptions-item label="商品标题">{{ payOrder.subject }}</el-descriptions-item>
        <el-descriptions-item label="商品内容">{{ payOrder.body }}</el-descriptions-item>
        <el-descriptions-item label="支付金额">￥{{ (payOrder.price / 100.0).toFixed(2) }}</el-descriptions-item>
        <el-descriptions-item label="创建时间">{{
          formattedCreateTime
        }}</el-descriptions-item>
        <el-descriptions-item label="过期时间">{{
          formattedExpireTime
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- 支付选择框 -->
    <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="提交支付中...">
      <!-- 支付宝 -->
      <el-descriptions title="选择支付宝支付" />
      <div class="pay-channel-container">
        <div class="box" v-for="channel in filteredChannels.alipay" :key="channel.code" @click="submit(channel.code)">
          <img :src="channel.icon" />
          <div class="title">{{ channel.name }}</div>
        </div>
      </div>
      <!-- 微信支付 -->
      <el-descriptions title="选择微信支付" style="margin-top: 20px;" />
      <div class="pay-channel-container">
        <div class="box" v-for="channel in filteredChannels.wx" :key="channel.code" @click="submit(channel.code)">
          <img :src="channel.icon" />
          <div class="title">{{ channel.name }}</div>
        </div>
      </div>
      <!-- 其它支付 -->
      <el-descriptions title="选择其它支付" style="margin-top: 20px;" />
      <div class="pay-channel-container">
        <div class="box" v-for="channel in filteredChannels.others" :key="channel.code" @click="submit(channel.code)">
          <img :src="channel.icon" />
          <div class="title">{{ channel.name }}</div>
        </div>
      </div>
    </el-card>

    <!-- 展示形式：二维码 URL -->
    <el-dialog :title="qrCode.title" :visible="dialogVisible" @update:visible="dialogVisible = $event" width="350px"
      append-to-body :close-on-press-escape="false">
      <qrcode-vue :value="qrCode.url" size="310" level="L" />
    </el-dialog>

    <!-- 展示形式：BarCode 条形码 -->
    <el-dialog :title="barCode.title" :visible="dialogVisible" @update:visible="dialogVisible = $event" width="500px"
      append-to-body :close-on-press-escape="false">
      <el-form ref="form" label-width="80px">
        <el-row>
          <el-col :span="24">
            <el-form-item label="条形码" prop="name">
              <el-input v-model="barCode.value" placeholder="请输入条形码" required />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <div style="text-align: right">
              或使用
              <el-link type="danger" target="_blank"
                href="https://baike.baidu.com/item/条码支付/10711903">(扫码枪/扫码盒)</el-link>
              扫码
            </div>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submit0(barCode.channelCode)"
            :disabled="barCode.value.length === 0">确认支付</el-button>
          <el-button @click="barCode.visible = false">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup lang="ts" name="PayCashier">
// import QrcodeVue from 'qrcode.vue'
import { getOrder, submitOrder, OrderSubmitRespVO } from '@/api/pay/order'
// import { PayChannelEnum, PayDisplayModeEnum, PayOrderStatusEnum } from "@/utils/constants"
import { PayChannelEnum, PayDisplayModeEnum, PayOrderStatusEnum } from "@/utils/constants"
const message = useMessage() // 消息弹窗
const router = useRouter() // 路由
const route = useRoute() // 路由
// name: "PayCashier",
// components: {
//   QrcodeVue,
// },

import alipayPcIcon from '@/assets/imgs/pay/icon/alipay_pc.svg';
import alipayWapIcon from '@/assets/imgs/pay/icon/alipay_wap.svg';
import alipayAppIcon from '@/assets/imgs/pay/icon/alipay_app.svg';
import alipayQrIcon from '@/assets/imgs/pay/icon/alipay_qr.svg';
import alipayBarIcon from '@/assets/imgs/pay/icon/alipay_bar.svg';
import wxPubIcon from '@/assets/imgs/pay/icon/wx_pub.svg';
import wxLiteIcon from '@/assets/imgs/pay/icon/wx_lite.svg';
import wxAppIcon from '@/assets/imgs/pay/icon/wx_app.svg';
import wxBarIcon from '@/assets/imgs/pay/icon/wx_bar.svg';
import wxNativeIcon from '@/assets/imgs/pay/icon/wx_native.svg';
import mockIcon from '@/assets/imgs/pay/icon/mock.svg';

const id = ref(0) // 请假编号
const returnUrl = ref() // 支付完的回调地址
const loading = ref(false) // 支付信息的 loading
const payOrder = ref({
  appId: undefined,
  subject: undefined,
  body: undefined,
  price: undefined,
  createTime: [],
  expireTime: []
}) // 支付信息
const channels = ref([
  {
    name: '支付宝 PC 网站支付',
    icon: alipayPcIcon,
    code: "alipay_pc"
  }, {
    name: '支付宝 Wap 网站支付',
    icon: alipayWapIcon,
    code: "alipay_wap"
  }, {
    name: '支付宝 App 网站支付',
    icon: alipayAppIcon,
    code: "alipay_app"
  }, {
    name: '支付宝扫码支付',
    icon: alipayQrIcon,
    code: "alipay_qr"
  }, {
    name: '支付宝条码支付',
    icon: alipayBarIcon,
    code: "alipay_bar"
  }, {
    name: '微信公众号支付',
    icon: wxPubIcon,
    code: "wx_pub"
  }, {
    name: '微信小程序支付',
    icon: wxLiteIcon,
    code: "wx_lite"
  }, {
    name: '微信 App 支付',
    icon: wxAppIcon,
    code: "wx_app"
  }, {
    name: '微信扫码支付',
    icon: wxNativeIcon,
    code: "wx_native"
  }, {
    name: '微信条码支付',
    icon: wxBarIcon,
    code: "wx_bar"
  }, {
    name: '模拟支付',
    icon: mockIcon,
    code: "mock"
  }, {
    name: '钱包支付',
    icon: mockIcon,
    code: "wallet"
  }])
const submitLoading = ref(false) // 提交支付的 loading
const interval = ref() // 定时任务，轮询是否完成支付
const qrCode = ref({ // 展示形式：二维码
  url: '',
  title: '',
  visible: false
})
const barCode = ref({ // 展示形式：条形码
  channelCode: '',
  value: '',
  title: '',
  visible: false
})

/** 初始化 **/
onMounted(() => {
  id.value = route.query.id
  if (route.query.returnUrl) {
    returnUrl.value = decodeURIComponent(route.query.returnUrl)
  }
  getDetail()
})

/** 计算属性 **/
const filteredChannels = computed(() => {
  const wxChannels = filteredChannelsWx();
  const alipayChannels = filteredChannelsAlipay();
  const othersChannels = filteredChannelsOthers();

  // 返回一个包含所有过滤后通道的数组或者其他数据结构
  return {
    wx: wxChannels,
    alipay: alipayChannels,
    others: othersChannels
  };
})

const filteredChannelsWx = () => {
  return channels.value.filter(channel => channel.code.indexOf('wx_') === 0);
}

const filteredChannelsAlipay = () => {
  return channels.value.filter(channel => channel.code.indexOf('alipay_') === 0);
}

const filteredChannelsOthers = () => {
  return channels.value.filter(channel => channel.code.indexOf('alipay_') === -1 && channel.code.indexOf('wx_') === -1);
}

const formattedCreateTime = computed(() => {
  return new Date(payOrder.value.createTime).toLocaleString();
});

const formattedExpireTime = computed(() => {
  return new Date(payOrder.value.expireTime).toLocaleString();
});

/** 获得支付信息 */
const getDetail = () => {
  // 1.1 未传递订单编号
  if (!id.value) {
    message.error('未传递支付单号，无法查看对应的支付信息')
    // goReturnUrl('cancel')
    return
  }
  getOrder(id.value).then(response => {
    // 1.2 无法查询到支付信息
    if (!response) {
      message.error('支付订单不存在，请检查！')
      // goReturnUrl('cancel')
      return
    }
    // 1.3 如果已支付、或者已关闭，则直接跳转
    if (response.status === PayOrderStatusEnum.SUCCESS.status) {
      message.success('支付成功')
      // goReturnUrl('success')
      return
    } else if (response.status === PayOrderStatusEnum.CLOSED.status) {
      message.error('无法支付，原因：订单已关闭')
      // goReturnUrl('close')
      return
    }

    // 2. 可以展示
    payOrder.value = response
  })
}

/** 提交支付 */
const submit = (channelCode: String) => {
  // 条形码支付，需要特殊处理
  if (channelCode === PayChannelEnum.ALIPAY_BAR.code) {
    barCode.value = {
      channelCode: channelCode,
      value: '',
      title: '“支付宝”条码支付',
      visible: true
    }
    return
  }
  // 微信公众号、小程序支付，无法在 PC 网页中进行
  if (channelCode === PayChannelEnum.WX_PUB.code) {
    message.error('微信公众号支付：不支持 PC 网站')
    return
  }
  if (channelCode === PayChannelEnum.WX_LITE.code) {
    message.error('微信小程序：不支持 PC 网站')
    return
  }

  // 默认的提交处理
  submit0(channelCode)
}

/** 提交支付 */
const submit0 = (channelCode: String) => {
  submitLoading.value = true
  submitOrder({
    id: id.value,
    channelCode: channelCode,
    returnUrl: location.href, // 支付成功后，支付渠道跳转回当前页；再由当前页，跳转回 {@link returnUrl} 对应的地址
    ...buildSubmitParam(channelCode)
  }).then(response => {
    // 直接返回已支付的情况，例如说扫码支付
    if (response.status === PayOrderStatusEnum.SUCCESS.status) {
      clearQueryInterval()
      message.success('支付成功！')
      goReturnUrl('success')
      return
    }
    // 展示对应的界面
    if (response.displayMode === PayDisplayModeEnum.URL.mode) {
      displayUrl(channelCode, response)
    } else if (response.displayMode === PayDisplayModeEnum.QR_CODE.mode) {
      displayQrCode(channelCode, response)
    } else if (response.displayMode === PayDisplayModeEnum.APP.mode) {
      displayApp(channelCode)
    }
    // 打开轮询任务
    createQueryInterval()
  }).catch(() => {
    submitLoading.value = false
  })
}
/** 构建提交支付的额外参数 */
const buildSubmitParam = (channelCode: string) => {
  // ① 支付宝 BarCode 支付时，需要传递 authCode 条形码
  if (channelCode === PayChannelEnum.ALIPAY_BAR.code) {
    return {
      "channelExtras": {
        "auth_code": barCode.value
      }
    }
  }
  // ② 微信 BarCode 支付时，需要传递 authCode 条形码
  if (channelCode === PayChannelEnum.WX_BAR.code) {
    return {
      "channelExtras": {
        "authCode": barCode.value
      }
    }
  }
  return {}
}
/** 提交支付后，URL 的展示形式 */
const displayUrl = (channelCode: String, data: OrderSubmitRespVO) => {
  location.href = data.displayContent
  submitLoading.value = false
}
/** 提交支付后（扫码支付） */
const displayQrCode = (channelCode: String, data: OrderSubmitRespVO) => {
  let title = '请使用手机浏览器“扫一扫”'
  if (channelCode === PayChannelEnum.ALIPAY_WAP.code) {
    // 考虑到 WAP 测试，所以引导手机浏览器搞
  } else if (channelCode.indexOf('alipay_') === 0) {
    title = '请使用支付宝“扫一扫”扫码支付'
  } else if (channelCode.indexOf('wx_') === 0) {
    title = '请使用微信“扫一扫”扫码支付'
  }
  qrCode.value = {
    title: title,
    url: data.displayContent,
    visible: true
  }
  submitLoading.value = false
}
/** 提交支付后（App） */
const displayApp = (channelCode: String) => {
  if (channelCode === PayChannelEnum.ALIPAY_APP.code) {
    message.error('支付宝 App 支付：无法在网页支付！')
  }
  if (channelCode === PayChannelEnum.WX_APP.code) {
    message.error('微信 App 支付：无法在网页支付！')
  }
  submitLoading.value = false
}

/** 轮询查询任务 */
const createQueryInterval = () => {
  if (interval.value) return
  interval.value = setInterval(() => {
    getOrder(id.value).then(response => {
      // 已支付
      if (response.status === PayOrderStatusEnum.SUCCESS.status) {
        clearQueryInterval()
        message.success('支付成功！')
        goReturnUrl('success')
      }
      // 已取消
      if (response.status === PayOrderStatusEnum.CLOSED.status) {
        clearQueryInterval()
        message.error('支付已关闭！')
        goReturnUrl('close')
      }
    })
  }, 1000 * 2)
}
/** 清空查询任务 */
const clearQueryInterval = () => {
  // 清空各种弹窗
  qrCode.value = {
    title: '',
    url: '',
    visible: false
  }
  // 清空任务
  clearInterval(interval.value)
  interval.value = undefined
}
/**
 * 回到业务的 URL
 *
 * @param payResult 支付结果
 *                  ① success：支付成功
 *                  ② cancel：取消支付
 *                  ③ close：支付已关闭
 */
const goReturnUrl = (payResult: string) => {
  // 清理任务
  clearQueryInterval()

  // 未配置的情况下，只能关闭
  if (!returnUrl.value) {
    tab.closePage()
    return
  }

  const url = returnUrl.value.indexOf('?') >= 0
    ? returnUrl.value + '&payResult=' + payResult
    : returnUrl.value + '?payResult=' + payResult
  // 如果有配置，且是 http 开头，则浏览器跳转
  if (returnUrl.value.indexOf('http') === 0) {
    location.href = url
  } else {
    tab.closePage(() => {
      router.push({
        path: url
      })
    })
  }
}
</script>
<style lang="scss" scoped>
.pay-channel-container {
  display: flex;
  margin-top: -10px;

  .box {
    width: 130px;
    border: 1px solid #e6ebf5;
    cursor: pointer;
    text-align: center;
    padding-top: 10px;
    padding-bottom: 5px;
    margin-right: 10px;

    img {
      width: 40px;
      height: 40px;
    }

    .title {
      padding-top: 5px;
    }
  }
}
</style>
